package tij4.concurrent.exercise.ex21;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

//class A implements Runnable {
//    @Override
//    public synchronized void run() {
//        while (!Thread.interrupted()) {
//            try {
//                wait();
//                System.out.println(this.getClass().getName());
//                notify();
//            } catch (InterruptedException e) {
//                e.printStackTrace();
//            }
//        }
//
//    }
//}
//
//class B implements Runnable {
//    private A a = new A();
//
//    @Override
//    public synchronized void run() {
//        while (!Thread.interrupted()) {
//            try {
//                System.out.println(this.getClass().getName());
//                TimeUnit.MILLISECONDS.sleep(200);
//                notifyAll();
//                wait();
//            }catch (InterruptedException e){
//                System.out.println("Exiting via interrupted");
//            }
//        }
//    }
//}
//public class Ex21 {
//    public static void main(String[] args) throws InterruptedException {
//        ExecutorService executorService = Executors.newCachedThreadPool();
//        executorService.execute(new A());
//        executorService.execute(new B());
//        TimeUnit.SECONDS.sleep(5);
//        executorService.shutdownNow();
//    }
//
//}

class A implements Runnable {
    private volatile boolean signal = false;

    public synchronized void run() {
        try {
            while (!signal) {   //wait() should always
                System.out.println("A.run() wait()");
                wait();
                signal = true;
                System.out.println("A is done waiting");
            }
        }catch (InterruptedException e) {
            System.out.println("A run() interrupted");
        }finally {
            System.out.println("Leaving A.run()");
        }
    }
    public synchronized void message() {
        System.out.println("Hi from A");
    }
}

class B implements Runnable {
    private A a;
    public A getA() {
        return a;
    }

    public B(A a) {
        this.a = a;
    }

    public synchronized void run() {
        try {
            TimeUnit.MILLISECONDS.sleep(2000);
            synchronized (a) {  //method calling notifyAll() must own monitor
                System.out.println("B.run() a.notifyAll()");
//                a.notify();   //这两个都可以
                notifyAll();
            }
        }catch (InterruptedException e) {
            System.out.println("B sleep interrupted");
        }
    }
}

public class Ex21 {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newCachedThreadPool();
        B b = new B(new A());
        executorService.execute(b.getA());
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        }catch (InterruptedException e) {
            System.out.println("main() sleep interrupted");
        }
        b.getA().message();
        executorService.execute(b);
        try {
            TimeUnit.MILLISECONDS.sleep(2500);
        }catch (InterruptedException e) {
            System.out.println("main() sleep interrupted");
        }
        executorService.shutdownNow();
    }
}